/**
 * @file order_manager.h
 * @brief 订单管理器的定义
 * 
 * @details 该文件定义了订单管理器（OrderManager）类，用于管理交易算法的订单。
 * 订单管理器隐藏了订单管理的复杂性，简化了交易策略的实现。
 * 它提供了创建、取消和移动订单的功能，并处理来自交易所的订单更新。
 * 
 * @author 原作者
 * @date 2023
 */

#pragma once

#include "common/macros.h"
#include "common/logging.h"

#include "exchange/order_server/client_response.h"

#include "om_order.h"
#include "risk_manager.h"

using namespace Common;

/**
 * @namespace Trading
 * @brief 交易相关的命名空间
 * 
 * @details 包含交易系统的核心组件，如订单、订单管理器、交易引擎等。
 */
namespace Trading {
  // 前向声明
  class TradeEngine;

  /**
   * @class OrderManager
   * @brief 订单管理器类
   * 
   * @details 管理交易算法的订单，隐藏订单管理的复杂性，简化交易策略的实现。
   * 该类提供了创建、取消和移动订单的功能，并处理来自交易所的订单更新。
   * 它与交易引擎和风险管理器密切协作，确保订单的正确执行和风险控制。
   */
  class OrderManager {
  public:
    /**
     * @brief 订单管理器的构造函数
     * 
     * @details 初始化订单管理器，设置日志记录器、交易引擎和风险管理器。
     * 这些组件在订单管理过程中起着关键作用。
     * 
     * @param logger 日志记录器，用于记录订单管理器的操作和状态
     * @param trade_engine 交易引擎，用于发送客户端请求
     * @param risk_manager 风险管理器，用于执行交易前的风险检查
     */
    OrderManager(Common::Logger *logger, TradeEngine *trade_engine, RiskManager& risk_manager)
        : trade_engine_(trade_engine), risk_manager_(risk_manager), logger_(logger) {
    }

    /**
     * @brief 处理来自客户端响应的订单更新，并更新所管理订单的状态
     * 
     * @details 根据交易所返回的客户端响应更新相应订单的状态。
     * 响应类型可能是接受、取消、成交、取消被拒绝或无效。
     * 根据不同的响应类型，订单的状态和数量将被相应地更新。
     * 
     * @param client_response 客户端响应对象指针，包含订单更新信息
     * @return void
     */
    auto onOrderUpdate(const Exchange::MEClientResponse *client_response) noexcept -> void {
      logger_->log("%:% %() % %\n", __FILE__, __LINE__, __FUNCTION__, Common::getCurrentTimeStr(&time_str_),
                   client_response->toString().c_str());
      auto order = &(ticker_side_order_.at(client_response->ticker_id_).at(sideToIndex(client_response->side_)));
      logger_->log("%:% %() % %\n", __FILE__, __LINE__, __FUNCTION__, Common::getCurrentTimeStr(&time_str_),
                   order->toString().c_str());

      switch (client_response->type_) {
        case Exchange::ClientResponseType::ACCEPTED: {
          order->order_state_ = OMOrderState::LIVE;
        }
          break;
        case Exchange::ClientResponseType::CANCELED: {
          order->order_state_ = OMOrderState::DEAD;
        }
          break;
        case Exchange::ClientResponseType::FILLED: {
          order->qty_ = client_response->leaves_qty_;
          if(!order->qty_)
            order->order_state_ = OMOrderState::DEAD;
        }
          break;
        case Exchange::ClientResponseType::CANCEL_REJECTED:
        case Exchange::ClientResponseType::INVALID: {
        }
          break;
      }
    }

    /**
     * @brief 发送具有指定属性的新订单，并更新传入的OMOrder对象
     * 
     * @details 创建并发送一个新的订单到交易所，并使用指定的属性更新传入的OMOrder对象。
     * 该方法会生成一个新的订单ID，并将订单状态设置为 PENDING_NEW。
     * 
     * @param order 要更新的OMOrder对象指针
     * @param ticker_id 证券标识符
     * @param price 订单价格
     * @param side 订单侧向（买入或卖出）
     * @param qty 订单数量
     * @return void
     */
    auto newOrder(OMOrder *order, TickerId ticker_id, Price price, Side side, Qty qty) noexcept -> void;

    /**
     * @brief 发送取消指定订单的请求，并更新传入的OMOrder对象
     * 
     * @details 为指定的订单创建并发送一个取消请求到交易所，并将订单状态更新为 PENDING_CANCEL。
     * 该方法不会立即取消订单，而是发送一个取消请求并等待交易所的确认。
     * 
     * @param order 要取消的OMOrder对象指针
     * @return void
     */
    auto cancelOrder(OMOrder *order) noexcept -> void;

    /**
     * @brief 移动指定侧向的单个订单，使其具有指定的价格和数量
     * 
     * @details 该方法用于移动订单，即根据需要取消现有订单并创建新订单。
     * 在发送订单前会执行风险检查，并更新传入的OMOrder对象。
     * 根据订单的当前状态和目标价格，执行不同的操作：
     * - 如果订单处于 LIVE 状态且价格变化，则取消现有订单
     * - 如果订单处于 INVALID 或 DEAD 状态且目标价格有效，则创建新订单
     * - 如果订单处于 PENDING_NEW 或 PENDING_CANCEL 状态，则不采取任何操作
     * 
     * @param order 要移动的OMOrder对象指针
     * @param ticker_id 证券标识符
     * @param price 目标价格，如果为 Price_INVALID 则表示不需要订单
     * @param side 订单侧向（买入或卖出）
     * @param qty 目标数量
     * @return void
     */
    auto moveOrder(OMOrder *order, TickerId ticker_id, Price price, Side side, Qty qty) noexcept {
      switch (order->order_state_) {
        case OMOrderState::LIVE: {
          if(order->price_ != price) {
            START_MEASURE(Trading_OrderManager_cancelOrder);
            cancelOrder(order);
            END_MEASURE(Trading_OrderManager_cancelOrder, (*logger_));
          }
        }
          break;
        case OMOrderState::INVALID:
        case OMOrderState::DEAD: {
          if(LIKELY(price != Price_INVALID)) {
            START_MEASURE(Trading_RiskManager_checkPreTradeRisk);
            const auto risk_result = risk_manager_.checkPreTradeRisk(ticker_id, side, qty);
            END_MEASURE(Trading_RiskManager_checkPreTradeRisk, (*logger_));
            if(LIKELY(risk_result == RiskCheckResult::ALLOWED)) {
              START_MEASURE(Trading_OrderManager_newOrder);
              newOrder(order, ticker_id, price, side, qty);
              END_MEASURE(Trading_OrderManager_newOrder, (*logger_));
            } else
              logger_->log("%:% %() % Ticker:% Side:% Qty:% RiskCheckResult:%\n", __FILE__, __LINE__, __FUNCTION__,
                           Common::getCurrentTimeStr(&time_str_),
                           tickerIdToString(ticker_id), sideToString(side), qtyToString(qty),
                           riskCheckResultToString(risk_result));
          }
        }
          break;
        case OMOrderState::PENDING_NEW:
        case OMOrderState::PENDING_CANCEL:
          break;
      }
    }

    /**
     * @brief 在指定的买入和卖出价格上设置指定数量的订单
     * 
     * @details 该方法用于同时管理买入和卖出两个方向的订单。
     * 它可能导致以下结果：
     * - 如果当前没有订单，则发送新订单
     * - 如果现有订单的价格或数量与指定的不同，则取消现有订单
     * - 如果买入或卖出价格指定为 Price_INVALID，表示我们不希望在该侧向有订单
     * 
     * 该方法内部使用 moveOrder 方法分别处理买入和卖出订单。
     * 
     * @param ticker_id 证券标识符
     * @param bid_price 买入价格，如果为 Price_INVALID 则表示不需要买入订单
     * @param ask_price 卖出价格，如果为 Price_INVALID 则表示不需要卖出订单
     * @param clip 订单数量，买入和卖出订单使用相同的数量
     * @return void
     */
    auto moveOrders(TickerId ticker_id, Price bid_price, Price ask_price, Qty clip) noexcept {
      {
        auto bid_order = &(ticker_side_order_.at(ticker_id).at(sideToIndex(Side::BUY)));
        START_MEASURE(Trading_OrderManager_moveOrder);
        moveOrder(bid_order, ticker_id, bid_price, Side::BUY, clip);
        END_MEASURE(Trading_OrderManager_moveOrder, (*logger_));
      }

      {
        auto ask_order = &(ticker_side_order_.at(ticker_id).at(sideToIndex(Side::SELL)));
        START_MEASURE(Trading_OrderManager_moveOrder);
        moveOrder(ask_order, ticker_id, ask_price, Side::SELL, clip);
        END_MEASURE(Trading_OrderManager_moveOrder, (*logger_));
      }
    }

    /**
     * @brief 获取指定证券标识符的买入和卖出订单的辅助方法
     * 
     * @details 该方法用于获取指定证券标识符的OMOrderSideHashMap，
     * 其中包含了该证券的买入和卖出订单。
     * 
     * @param ticker_id 证券标识符
     * @return 指向该证券的OMOrderSideHashMap的指针
     */
    auto getOMOrderSideHashMap(TickerId ticker_id) const {
      return &(ticker_side_order_.at(ticker_id));
    }

    /**
     * @brief 删除的默认构造函数、拷贝构造函数、移动构造函数和赋值运算符
     * 
     * @details 订单管理器类不允许默认构造、拷贝或移动，以确保其安全使用。
     * 这些操作被显式删除，以防止意外创建多个订单管理器实例或意外复制。
     */
    OrderManager() = delete;

    /**
     * @brief 删除的拷贝构造函数
     */
    OrderManager(const OrderManager &) = delete;

    /**
     * @brief 删除的移动构造函数
     */
    OrderManager(const OrderManager &&) = delete;

    /**
     * @brief 删除的拷贝赋值运算符
     */
    OrderManager &operator=(const OrderManager &) = delete;

    /**
     * @brief 删除的移动赋值运算符
     */
    OrderManager &operator=(const OrderManager &&) = delete;

  private:
    /**
     * @brief 父交易引擎对象，用于发送客户端请求
     * 
     * @details 指向交易引擎的指针，订单管理器通过它发送新订单和取消订单的请求。
     */
    TradeEngine *trade_engine_ = nullptr;

    /**
     * @brief 风险管理器，用于执行交易前的风险检查
     * 
     * @details 引用风险管理器对象，在发送新订单前用于检查交易风险。
     * 这是一个常量引用，表示风险管理器在订单管理器的生命周期内不会改变。
     */
    const RiskManager& risk_manager_;

    /**
     * @brief 时间字符串缓存
     * 
     * @details 用于在日志记录中存储当前时间的字符串表示，避免重复创建。
     */
    std::string time_str_;
    
    /**
     * @brief 日志记录器指针
     * 
     * @details 用于记录订单管理器的操作和状态变化的日志记录器。
     */
    Common::Logger *logger_ = nullptr;

    /**
     * @brief 从证券标识符到侧向再到订单的哈希映射容器
     * 
     * @details 使用二维数组实现的哈希表，用于存储和管理所有证券的买入和卖出订单。
     * 这是订单管理器的核心数据结构，存储了所有管理的订单。
     */
    OMOrderTickerSideHashMap ticker_side_order_;

    /**
     * @brief 用于设置新订单请求的订单ID
     * 
     * @details 每次创建新订单时使用并递增的订单ID，确保每个订单都有唯一的标识符。
     * 初始值为1，每次创建新订单后增加1。
     */
    OrderId next_order_id_ = 1;
  };
}
